using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using ProjectEuler.Core.Helpers;

namespace ProjectEuler.Core
{
    public class Problem21 : IProjectEulerProblem
    {
        protected IDictionary<int,int> SumOfProperDivisorsFrom1To(int n)
        {
            var dict = new Dictionary<int,int>();
            for (int i = 2; i <= n; i++)
            {
                dict.Add(i, MathHelper.FactorsOf(i).Sum() - i);    // don't include the number itself in the list/sum
            }
            return dict;
        }

        protected IList<int> GetAmicableNumbers()
        {
            var factorsums = SumOfProperDivisorsFrom1To(10000);
            var amicables = new List<int>();
            foreach (var kvp in factorsums)
            {
                if(factorsums.ContainsKey(kvp.Value) && factorsums[kvp.Value] == kvp.Key)
                {
                    if (kvp.Value != kvp.Key)
                    {
                        if (!amicables.Contains(kvp.Key))
                        {
                            amicables.Add(kvp.Key);
                        }
                        if (!amicables.Contains(kvp.Value))
                        {
                            amicables.Add(kvp.Value);
                        }
                    }
                }
            }
            return amicables;
        }

        public int Number
        {
            get { return 21; }
        }

        public string Description
        {
            get { return "Evaluate the sum of all the amicable numbers under 10000"; }
        }

        public string Answer
        {
            get { return GetAmicableNumbers().Sum().ToString(); }
        }
    }

    [TestFixture]
    public class Problem21Tests : Problem21
    {
        [Test]
        public void The_sum_of_proper_divisors_of_220_are_284()
        {
            var factors = MathHelper.FactorsOf(220);
            var sum = factors.Sum() - 220;
            Assert.AreEqual(284, sum);
        }

        [Test]
        public void The_sum_of_proper_divisors_of_2_are_1()
        {
            var factors = MathHelper.FactorsOf(2);
            var sum = factors.Sum() - 2;
            Assert.AreEqual(1, sum);
        }

        [Test]
        public void Can_get_all_amicable_numbers()
        {
            var amicables = GetAmicableNumbers();
            Assert.NotNull(amicables);
        }
    }
}